package com.vegetable.modules.service.finance.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vegetable.common.constant.CommonConstant;
import com.vegetable.common.utils.Constant;
import com.vegetable.common.utils.PageUtils;
import com.vegetable.common.utils.Query;
import com.vegetable.common.utils.R;
import com.vegetable.modules.entity.baseData.AccountDetails;
import com.vegetable.modules.entity.baseData.AddressBook;
import com.vegetable.modules.entity.finance.FinancialCollection;
import com.vegetable.modules.entity.finance.FinancialCollectionDetail;
import com.vegetable.modules.entity.finance.po.FinancialCollectionAddPO;
import com.vegetable.modules.entity.finance.po.FinancialCollectionDetailPO;
import com.vegetable.modules.entity.finance.po.FinancialCollectionPO;
import com.vegetable.modules.entity.outbound.SalesOut;
import com.vegetable.modules.entity.outbound.SalesOutDeduction;
import com.vegetable.modules.entity.outbound.po.SalesOutDeductionAddPO;
import com.vegetable.modules.mapper.finance.FinancialCollectionMapper;
import com.vegetable.modules.service.baseData.IAccountDetailsService;
import com.vegetable.modules.service.baseData.IAddressBookService;
import com.vegetable.modules.service.baseData.IFundAccountService;
import com.vegetable.modules.service.finance.IFinancialCollectionDetailService;
import com.vegetable.modules.service.finance.IFinancialCollectionService;
import com.vegetable.modules.service.outbound.ISalesOutDeductionService;
import com.vegetable.modules.service.outbound.ISalesOutService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 财务收款管理 服务实现类
 * </p>
 *
 * @author wangruijie
 * @since 2024-04-13
 */
@Slf4j
@Service
@AllArgsConstructor
public class FinancialCollectionServiceImpl extends ServiceImpl<FinancialCollectionMapper, FinancialCollection> implements IFinancialCollectionService {

    // 通讯录
    private IAddressBookService addressBookService;
    // 往来明细
    private IAccountDetailsService accountDetailsService;
    // 销售出库
    private ISalesOutService salesOutService;

    private IFundAccountService accountService;
    // 回款明细表
    private IFinancialCollectionDetailService detailService;

    private ISalesOutDeductionService salesOutDeductionService;
    /**
     * 销售收款列表查询
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        String docNo = (String)params.get("docNo");
        // 状态0未对冲，1已对冲
        Object state = params.get("state");
        String startTime = (String)params.get("startTime");
        String endTime = (String)params.get("endTime");
        IPage<FinancialCollection> page = this.page(
                new Query<FinancialCollection>().getPage(params),
                new QueryWrapper<FinancialCollection>()
                        .between(StringUtils.isNotBlank(startTime), "order_time", startTime, endTime)
                        .eq(ObjectUtils.isNotEmpty(state),"state", state)
                        .eq(ObjectUtils.isNotEmpty(params.get("customerId")),"customer_id", params.get("customerId"))
                        .like(StringUtils.isNotBlank(docNo),"doc_no", docNo)
                        .orderByDesc("not_allocated_money", "create_time")
        );

        return new PageUtils(page);
    }

    /**
     * 新增销售收款
     * 1，销售回款表新增
     * 2，循环回款明细挨个新增
     * 3，循环更新未对账金额（如果此刻做更新，可在下次新增销售回款时，查出准确剩余未对账）
     * @param po null
     * @return R
     * @author wrj
     * @since 2024/3/7 下午4:35
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveCollection(FinancialCollectionAddPO po) {
        FinancialCollection order = new FinancialCollection();
        List<FinancialCollectionDetail> detailList = new ArrayList<>();
        BeanUtils.copyProperties(po, order);
        if (order.getId() == null){
            order.setDocNo(CommonConstant.XSSK+ baseMapper.getNextCode());

        }
        // 明细金额合并后就是此次的已分配金额
        BigDecimal allocatedMoney = po.getDetailPOList().stream().map(e -> e.getMoney()).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 未分配金额
        order.setNotAllocatedMoney(NumberUtil.sub(po.getMoney(), allocatedMoney));
        this.saveOrUpdate(order);
        return R.data(order.getId());
    }

    @Override
    @Transactional
    public R allocatedCollection(FinancialCollectionAddPO po) throws Exception {
        List<FinancialCollectionDetailPO> detailPOList = po.getDetailPOList();
        if(CollectionUtil.isEmpty(detailPOList)){
            throw new Exception("回款分配不能为空");
        }
        log.info("开始保存回款明细，供:{}条", po.getDetailPOList().size());
        FinancialCollection order = getById(po.getId());
        if(Objects.isNull(order)){
            throw new Exception("回款记录不存在，请检查后重试");
        }
        List<SalesOutDeductionAddPO> pos = new ArrayList<>();
        for (FinancialCollectionDetailPO detailPO : po.getDetailPOList()) {
            SalesOutDeductionAddPO deductionAddPO = new SalesOutDeductionAddPO();
            deductionAddPO.setOutId(detailPO.getOrderId());
            // 3代表回款
            deductionAddPO.setDeductionType(3);
            deductionAddPO.setDeductionMoney(detailPO.getMoney());
            deductionAddPO.setFcId(po.getId());
            deductionAddPO.setRemark(detailPO.getRemark());
            pos.add(deductionAddPO);
        }
        // 新增回款
        salesOutDeductionService.batchAddDeduction(pos);
        // 更新回款单的已分配金额
        updateAllocatedMoney(po.getId());
        return R.data(order.getId());
    }

    /**
     * 更新回款单的已分配金额
     * @param poId 回款单id
     */
    private void updateAllocatedMoney(Long poId) {
        // 更新已分配金额
        List<SalesOutDeduction> allocated = salesOutDeductionService.getSalesOutDeductionByFCId(poId);
        BigDecimal allocatedMoney = allocated.stream().filter(el -> el.getDeductionType() == 3).map(SalesOutDeduction::getDeductionMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        FinancialCollection fc = getById(poId);
        FinancialCollection updater = new FinancialCollection();
        updater.setId(fc.getId());
        updater.setNotAllocatedMoney(NumberUtil.sub(fc.getMoney(), allocatedMoney));
        updateById(updater);
    }

    /**
     * 根据id查询销售收款详情
     * @param id null
     * @return R
     * @author wrj
     * @since 2024/7/6 下午2:24
     */
    @Override
    public R detailCollection(Long id) {
        FinancialCollection selectById = baseMapper.selectById(id);
        if (selectById == null){
            return R.fail("订单不存在");
        }
//        List<FinancialCollectionDetail> detailList = detailService.findByMainId(selectById.getId());
//        selectById.setDetailPOList(detailList);
        return R.data(selectById);
    }

    /**
     * 根据出库订单id查询 回款明细情况
     * @param id null
     * @return R
     * @author wrj
     * @since 2024/7/6 下午2:43
     */
    @Override
    public R<List<FinancialCollectionDetail>> hedgedDetailList(Long id) {
        QueryWrapper<FinancialCollectionDetail> wrapper = new QueryWrapper();
        wrapper.eq("order_id", id);
        List<FinancialCollectionDetail> detailList = detailService.getBaseMapper().selectList(wrapper);
        if (!CollectionUtils.isEmpty(detailList)){
            for (FinancialCollectionDetail detail:detailList) {
                FinancialCollection collection = baseMapper.selectById(detail.getMainId());
                if (collection != null){
                    detail.setMainOrderNo(collection.getDocNo());
                }
            }
        }
        return R.data(detailList);
    }

    /**
     * 对冲销售收款确认
     * 1，根据出库单id查询出库单不能为空
     * 2，循环该出库单涉及的一或者多个销售回款明细
     * 3，循环挨个新增往来明细做记录
     * 4，按照收款账户分组汇总，对应每个收款账户收多少钱
     * 5，更新通讯录客商的应收总金额
     * 6，遍历账户Map更新，账户的总收款
     * @param po null
     * @return R
     * @author wrj
     * @since 2024/3/7 下午4:35
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R submitCollection(FinancialCollectionPO po) throws Exception {
        // 参数是出库单id，所以不能这么操作，临时注释掉
        SalesOut selectById = salesOutService.getById(po.getId());
        if (selectById == null){
            throw new Exception("销售出库单不存在");
        }

        log.info("新增客商的往来明细开始--->");
        saveAccountDetails(selectById.getCustomerId(), selectById, po);
        // 更新客商的应收金额
        updateArrears(selectById.getCustomerId(), po.getReceivedMoney());

        log.info("根据当前销售出库单id查询对应有几个回款明细");
        R<List<FinancialCollectionDetail>> r = hedgedDetailList(po.getId());
        if (r.isSuccess()){
            List<FinancialCollectionDetail> detailList = r.getData();
            Map<Long, BigDecimal> fundAccountMap = new HashMap<>();
            for (FinancialCollectionDetail detail : detailList) {
                log.info("按照收款账户统计");
                FinancialCollection collection = baseMapper.selectById(detail.getMainId());
                if (fundAccountMap.containsKey(collection.getAccountId())){
                    BigDecimal v_b = fundAccountMap.get(collection.getAccountId());
                    v_b = v_b.add(detail.getMoney());
                    fundAccountMap.put(collection.getAccountId(), v_b);
                }else {
                    fundAccountMap.put(collection.getAccountId(), detail.getMoney());
                }
            }
            // 因为一个出库单可能对应多个销售回款，所以可能对应多个账户更新总收款
            for (Long accountId:fundAccountMap.keySet()) {
//                FundAccount account_in = accountService.getById(accountId);
//                if (account_in != null){
//                    log.info("对冲后，收款账户更新前：{}", JSON.toJSONString(account_in));
//                    BigDecimal totalReceipts = account_in.getTotalReceipts();
//                    totalReceipts = totalReceipts.add(fundAccountMap.get(accountId));
//                    account_in.setTotalReceipts(totalReceipts);
//                    log.info("对冲后，收款账户更新前：{}", JSON.toJSONString(account_in));
//                    accountService.updateById(account_in);
//                }
                accountService.addReceipts(accountId, fundAccountMap.get(accountId), Constant.MoneyTYPE.SALES_IN, selectById.getDocNo(), selectById.getId(), selectById.getCustomerName());
            }
        }
        // 设置为已对冲
        selectById.setNoReturn(po.getNoReturn());
        selectById.setAgentDiscount(po.getAgentDiscount());
        selectById.setBonus(po.getBonus());
        selectById.setHedgingState(1);
        selectById.setRemark(po.getRemark());
        salesOutService.updateById(selectById);
        return R.status(true);
    }

    /**
     * 新增客商的往来明细
     * @param customerId null
     * @return void
     * @author wrj
     * @since 2024/3/22 上午11:44
     */
    private void saveAccountDetails(Long customerId, SalesOut selectById, FinancialCollectionPO po){
        // 生成代办的往来明细
        AccountDetails accountDetails = new AccountDetails();
        accountDetails.setStaffType(1); // 客商
        accountDetails.setPersonId(customerId);
        accountDetails.setDetailType(2); // 付款
        accountDetails.setOrderId(selectById.getId());
        accountDetails.setOrderTime(selectById.getOrderTime());
        // 对应的销售收款
        accountDetails.setDocNo(selectById.getDocNo());
        // 回款金额
        accountDetails.setMoney(po.getReceivedMoney());
        accountDetails.setAgentDiscount(po.getAgentDiscount());
        accountDetails.setBonus(po.getBonus());
        accountDetails.setNoReturn(po.getNoReturn());
        log.info("销售收款保存客商的的往来明细：{}", JSON.toJSONString(accountDetails));
        accountDetailsService.save(accountDetails);
    }

    /**
     * 更新客商的应收金额
     *
     * @param money null
     * @return void
     * @author wrj
     * @since 2024/3/22 上午11:47
     */
    private void updateArrears(Long customerId, BigDecimal money){
        // 更新待办的应收金额
        AddressBook addressBook = addressBookService.getById(customerId);
        BigDecimal arrears = addressBook.getArrears();
        // 减去该订单代办应收金额
        arrears = arrears.subtract(money);
        addressBook.setArrears(arrears);
        log.info("更新后客商的应收金额：{},{}", JSON.toJSONString(addressBook));
        addressBookService.updateById(addressBook);
    }
    /**
     * 删除销售收款
     * @param id null
     * @return R
     * @author wrj
     * @since 2024/3/7 下午4:35
     */
    @Override
    public R deleteCollection(Long id) throws Exception {
        FinancialCollection selectById = baseMapper.selectById(id);
        if (selectById == null){
            throw new Exception("订单不存在");
        }
        if (selectById.getState().intValue() != 0){
            throw new Exception("订单不是未对账状态，不能删除");
        }
        baseMapper.deleteById(id);
        return R.status(true);
    }

    @Override
    public Boolean deleteDeduction(Long id) throws Exception {
        SalesOutDeduction deduction = salesOutDeductionService.getById(id);
        if (deduction == null){
            throw new Exception("收款明细不存在");
        }
        salesOutDeductionService.removeById(id);
        updateAllocatedMoney(deduction.getFcId());
        return Boolean.TRUE;
    }
}
